import 'dayjs/locale/zh-cn'
import dayjs from 'dayjs'
import customParseFormat from 'dayjs/plugin/customParseFormat'
import isBetween from 'dayjs/plugin/isBetween'
import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
import isToday from 'dayjs/plugin/isToday'
import isTomorrow from 'dayjs/plugin/isTomorrow'
import isYesterday from 'dayjs/plugin/isYesterday'
import localeData from 'dayjs/plugin/localeData'
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
import relativeTime from 'dayjs/plugin/relativeTime'
import weekday from 'dayjs/plugin/weekday'
import weekOfYear from 'dayjs/plugin/weekOfYear'
import weekYear from 'dayjs/plugin/weekYear'

// 按需引入插件
dayjs.extend(relativeTime)
dayjs.extend(customParseFormat)
dayjs.extend(weekday)
dayjs.extend(localeData)
dayjs.extend(isToday)
dayjs.extend(isYesterday)
dayjs.extend(isTomorrow)
dayjs.extend(isSameOrBefore)
dayjs.extend(isSameOrAfter)
dayjs.extend(isBetween)
dayjs.extend(quarterOfYear)
dayjs.extend(weekOfYear)
dayjs.extend(weekYear)

// 设置语言为中文
dayjs.locale('zh-cn')

/**
 * 日期格式化模板类型定义
 * @type {Object.<string, string>}
 */
export const FORMAT_TYPE = {
  /** 日期时间 */
  DATETIME: 'YYYY-MM-DD HH:mm:ss',
  /** 日期 */
  DATE: 'YYYY-MM-DD',
  /** 时间 */
  TIME: 'HH:mm:ss',
  /** 年月 */
  YEAR_MONTH: 'YYYY年MM月',
  /** 月日 */
  MONTH_DAY: 'MM月DD日',
  /** 周 */
  WEEK: 'dddd',
  /** 月 */
  MONTH: 'MM',
  /** 年 */
  YEAR: 'YYYY',
  /** 时分 */
  HOUR_MINUTE: 'HH:mm',
}

/**
 * 日期工具类
 * @type {DayUtil}
 */
export const $day = {
  /**
   * 原始 dayjs 实例
   */
  dayjs,

  /**
   * 获取当前时间
   */
  now: () => dayjs(),

  /**
   * 格式化日期
   * @param {DateType} date 日期
   * @param {string} [format=FORMAT_TYPE.DATETIME] 格式化模板
   */
  format: (date, format = FORMAT_TYPE.DATETIME) => dayjs(date).format(format),

  /**
   * 获取相对时间
   * @param {DateType} date 日期
   */
  fromNow: date => dayjs(date).fromNow(),

  /**
   * 计算年龄
   * @param {DateType} birthday 生日
   */
  getAge: birthday => {
    const birthdayDate = dayjs(birthday)
    const age = dayjs().diff(birthdayDate, 'year')
    if (dayjs().isBefore(birthdayDate.add(age, 'year'))) {
      return age - 1
    }
    return age
  },

  /**
   * 获取下一个生日
   * @param {DateType} birthday 生日
   */
  getNextBirthday: birthday => {
    const birthdayDate = dayjs(birthday)
    const age = dayjs().diff(birthdayDate, 'year')
    const nextBirthday = birthdayDate.add(age + 1, 'year')
    return {
      date: nextBirthday,
      days: nextBirthday.diff(dayjs(), 'day'),
    }
  },

  /**
   * 是否今天
   * @param {DateType} date 日期
   */
  isToday: date => dayjs(date).isToday(),

  /**
   * 是否昨天
   * @param {DateType} date 日期
   */
  isYesterday: date => dayjs(date).isYesterday(),

  /**
   * 是否明天
   * @param {DateType} date 日期
   */
  isTomorrow: date => dayjs(date).isTomorrow(),

  /**
   * 是否周末
   * @param {DateType} date 日期
   */
  isWeekend: date => {
    const day = dayjs(date).day()
    return day === 0 || day === 6
  },

  /**
   * 是否同一天
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   */
  isSameDay: (date1, date2) => dayjs(date1).isSame(date2, 'day'),

  /**
   * 是否同一周
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   */
  isSameWeek: (date1, date2) => dayjs(date1).isSame(date2, 'week'),

  /**
   * 是否同一月
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   */
  isSameMonth: (date1, date2) => dayjs(date1).isSame(date2, 'month'),

  /**
   * 是否同一年
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   */
  isSameYear: (date1, date2) => dayjs(date1).isSame(date2, 'year'),

  /**
   * 是否在指定日期之前
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   * @param {dayjs.OpUnitType} [unit] 单位
   */
  isBefore: (date1, date2, unit) => dayjs(date1).isBefore(date2, unit),

  /**
   * 是否在指定日期之后
   * @param {DateType} date1 日期1
   * @param {DateType} date2 日期2
   * @param {dayjs.OpUnitType} [unit] 单位
   */
  isAfter: (date1, date2, unit) => dayjs(date1).isAfter(date2, unit),

  /**
   * 是否在指定日期范围内
   * @param {DateType} date 日期
   * @param {DateType} start 开始日期
   * @param {DateType} end 结束日期
   * @param {dayjs.OpUnitType} [unit] 单位
   */
  isBetween: (date, start, end, unit) => dayjs(date).isBetween(start, end, unit),

  /**
   * 获取季度
   * @param {DateType} [date=dayjs()] 日期
   */
  getQuarter: (date = dayjs()) => dayjs(date).quarter(),

  /**
   * 获取周数
   * @param {DateType} [date=dayjs()] 日期
   */
  getWeek: (date = dayjs()) => dayjs(date).week(),

  /**
   * 获取月份天数
   * @param {DateType} [date=dayjs()] 日期
   */
  getDaysInMonth: (date = dayjs()) => dayjs(date).daysInMonth(),

  /**
   * 获取是周几
   * @param {DateType} [date=dayjs()] 日期
   */
  getDayOfWeek: (date = dayjs()) => dayjs(date).day(),

  /**
   * 获取是几号
   * @param {DateType} [date=dayjs()] 日期
   */
  getDayOfMonth: (date = dayjs()) => dayjs(date).date(),

  /**
   * 获取年份
   * @param {DateType} [date=dayjs()] 日期
   */
  getYear: (date = dayjs()) => dayjs(date).year(),

  /**
   * 获取月份
   * @param {DateType} [date=dayjs()] 日期
   */
  getMonth: (date = dayjs()) => dayjs(date).month() + 1,

  /**
   * 增加指定时间
   * @param {DateType} date 日期
   * @param {number} value 值
   * @param {dayjs.ManipulateType} [unit='day'] 单位
   */
  add: (date, value, unit = 'day') => dayjs(date).add(value, unit),

  /**
   * 减少指定时间
   * @param {DateType} date 日期
   * @param {number} value 值
   * @param {dayjs.ManipulateType} [unit='day'] 单位
   */
  subtract: (date, value, unit = 'day') => dayjs(date).subtract(value, unit),

  /**
   * 获取开始时间
   * @param {DateType} date 日期
   * @param {dayjs.OpUnitType} [unit='day'] 单位
   */
  startOf: (date, unit = 'day') => dayjs(date).startOf(unit),

  /**
   * 获取结束时间
   * @param {DateType} date 日期
   * @param {dayjs.OpUnitType} [unit='day'] 单位
   */
  endOf: (date, unit = 'day') => dayjs(date).endOf(unit),
}

/**
 * 日期类型
 * @typedef {string|Date|number|dayjs.Dayjs} DateType
 */

/**
 * 日期工具类类型定义
 * @typedef {Object} DayUtil
 * @property {dayjs.Dayjs} dayjs - 原始 dayjs 实例
 * @property {() => dayjs.Dayjs} now - 获取当前时间
 * @property {(date: DateType, format?: string) => string} format - 格式化日期
 * @property {(date: DateType) => string} fromNow - 获取相对时间
 * @property {(birthday: DateType) => number} getAge - 计算年龄
 * @property {(birthday: DateType) => {date: dayjs.Dayjs, days: number}} getNextBirthday - 获取下一个生日
 * @property {(date: DateType) => boolean} isToday - 是否今天
 * @property {(date: DateType) => boolean} isYesterday - 是否昨天
 * @property {(date: DateType) => boolean} isTomorrow - 是否明天
 * @property {(date: DateType) => boolean} isWeekend - 是否周末
 * @property {(date1: DateType, date2: DateType) => boolean} isSameDay - 是否同一天
 * @property {(date1: DateType, date2: DateType) => boolean} isSameWeek - 是否同一周
 * @property {(date1: DateType, date2: DateType) => boolean} isSameMonth - 是否同一月
 * @property {(date1: DateType, date2: DateType) => boolean} isSameYear - 是否同一年
 * @property {(date1: DateType, date2: DateType, unit?: dayjs.OpUnitType) => boolean} isBefore - 是否在指定日期之前
 * @property {(date1: DateType, date2: DateType, unit?: dayjs.OpUnitType) => boolean} isAfter - 是否在指定日期之后
 * @property {(date: DateType, start: DateType, end: DateType, unit?: dayjs.OpUnitType) => boolean} isBetween - 是否在指定日期范围内
 * @property {(date?: DateType) => number} getQuarter - 获取季度
 * @property {(date?: DateType) => number} getWeek - 获取周数
 * @property {(date?: DateType) => number} getDaysInMonth - 获取月份天数
 * @property {(date?: DateType) => number} getDayOfWeek - 获取是周几
 * @property {(date?: DateType) => number} getDayOfMonth - 获取是几号
 * @property {(date?: DateType) => number} getYear - 获取年份
 * @property {(date?: DateType) => number} getMonth - 获取月份
 * @property {(date: DateType, value: number, unit?: dayjs.ManipulateType) => dayjs.Dayjs} add - 增加指定时间
 * @property {(date: DateType, value: number, unit?: dayjs.ManipulateType) => dayjs.Dayjs} subtract - 减少指定时间
 * @property {(date: DateType, unit?: dayjs.OpUnitType) => dayjs.Dayjs} startOf - 获取开始时间
 * @property {(date: DateType, unit?: dayjs.OpUnitType) => dayjs.Dayjs} endOf - 获取结束时间
 */
